#include "mystdio.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>


MYFILE *my_fopen(const char *path, const char *mode) //打开文件
{
    assert(path);
    assert(mode);

    //mode = 只读r/只写w/追加a
    int flag = 0;
    if(strcmp(mode,"r") == 0) flag |= O_RDONLY; //只读方式打开
    else if(strcmp(mode,"w") == 0) flag |= O_WRONLY|O_CREAT|O_TRUNC; //只写方式打开文件，文件不存在就创建，覆写文件
    else if(strcmp(mode,"a") == 0) flag |= O_WRONLY|O_CREAT|O_APPEND; //只写方式打开文件，文件不存在就创建，追加写入
    else { return NULL; }

    int fd = 0;
    umask(002); //默认权限掩码002 权限为rw-rw-r--
    if(flag & O_CREAT) fd = open(path,flag,0666);
    else fd = open(path,flag);

    if(fd < 0) { return NULL; }


    MYFILE* file = (MYFILE*)malloc(sizeof(MYFILE));
    if(!file) 
    {
        perror("malloc MYFILE error\n");
        exit(EOF);
    }

    file->fd = fd; //写入文件描述符
    file->flags = BUFF_LINE; //初定为行刷新策略
    file->current = 0; //缓冲区下标置0
    memset(file->outputbuffer,'\0',sizeof(file->outputbuffer)); //初始化缓冲区为\0

    return file;
}

size_t my_fwrite(const void *ptr, size_t size, size_t nmemb,MYFILE *fp) //写入文件
{
    if(fp->current == NUM) my_fflush(fp);

    size_t sz = 0;
    size_t write_size = size*nmemb; //要写入的字节数
    size_t cap = NUM - fp->current; //剩余容量
    if(write_size <= cap) //如果容量足够
    {
        memcpy((fp->outputbuffer)+(fp->current),ptr,write_size);
        fp->current += write_size;
    }
    else //缓冲区容量不足
    {
        my_fflush(fp);
        write(fp->fd,ptr,write_size);
    }
    sz = write_size;

    if(fp->flags & BUFF_LINE) //行刷新
    {
        if((fp->outputbuffer)[(fp->current-1)] == '\n') my_fflush(fp);
    }
    else if(fp->flags & BUFF_ALL) //全刷新
    {
        if((fp->current) == NUM) my_fflush(fp);
    }

    return sz;
}

size_t my_fread(void *ptr, size_t size, size_t nmemb,MYFILE *fp) //读取文件
{
    assert(fp);

    size_t sz = size*nmemb;
    sz = read(fp->fd,ptr,sz); //因为缓冲区问题，直接IO进行读取
    return sz;
}

int my_fclose(MYFILE *fp) //关闭文件
{
    assert(fp);

    if(fp->current > 0) my_fflush(fp);

    close(fp->fd);

    free(fp);

    fp = NULL;

    return 0;
}

int my_fflush(MYFILE *fp) //刷新缓冲区
{
    assert(fp);
    if(fp->current > 0)
    {
        write(fp->fd,fp->outputbuffer,fp->current); //写入内核缓存
    }
    fsync(fp->fd); //强行刷新内核缓存
    fp->current = 0;
    return 0;
}